package com.leonzhangxf.spel.reference;

import com.leonzhangxf.spel.reference.bean.Inventor;
import com.leonzhangxf.spel.reference.bean.Society;
import lombok.Getter;
import lombok.Setter;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Collection Selection
 * <p>
 * Selection is a powerful expression language feature that lets you
 * transform a source collection into another collection by selecting from its entries.
 * <p>
 * Selection uses a syntax of .?[selectionExpression].
 * It filters the collection and returns a new collection that contain a subset of the original elements.
 * For example, selection lets us easily get a list of Serbian inventors, as the following example shows:
 *
 * <code>
 * List<Inventor> list = (List<Inventor>) parser.parseExpression(
 * "Members.?[Nationality == 'Serbian']").getValue(societyContext);
 * </code>
 *
 * <p>
 * Selection is possible upon both lists and maps. For a list,
 * the selection criteria is evaluated against each individual list element.
 * Against a map, the selection criteria is evaluated against each map entry (objects of the Java type Map.Entry).
 * Each map entry has its key and value accessible as properties for use in the selection.
 * <p>
 * The following expression returns a new map that consists of those elements of
 * the original map where the entry value is less than 27:
 * <code>
 * Map newMap = parser.parseExpression("map.?[value<27]").getValue();
 * </code>
 * In addition to returning all the selected elements, you can retrieve only the first or the last value.
 * To obtain the first entry matching the selection, the syntax is .^[selectionExpression].
 * To obtain the last matching selection, the syntax is .$[selectionExpression].
 *
 * @author leonzhangxf
 * @date 20190427
 */
public class CollectionSelection {

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();

        Society society = new Society();
        society.getMembers().add(new Inventor("AAA", "Serbian"));
        society.getMembers().add(new Inventor("BBB", "Serbian"));
        society.getMembers().add(new Inventor("CCC", "China"));
        society.getMembers().add(new Inventor("DDD", "China"));
        society.getMembers().add(new Inventor("EEE", "America"));

        context.setRootObject(society);

        List<Inventor> list = (List<Inventor>) parser.parseExpression(
            "Members.?[Nationality == 'Serbian']").getValue(context);
        System.out.println(list);

        Map<String, Integer> map = new HashMap<>();
        map.put("L", 10);
        map.put("B", 10);
        map.put("C", 50);
        map.put("A", 10);

        Container container = new Container();
        container.setMap(map);

        Map newMap = parser.parseExpression("map.?[value<27]").getValue(container, Map.class);
        System.out.println(newMap);

        System.out.println(parser.parseExpression("#root.?[value<27]").getValue(map, Map.class));
    }

    @Setter
    @Getter
    private static class Container {
        private Map map;
    }
}
